package cn.com.bluemoon.daps.system.service.impl;

import cn.com.bluemoon.daps.common.constant.DapConstant;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.exception.DapException;
import cn.com.bluemoon.daps.system.dto.DatasourceDto;
import cn.com.bluemoon.daps.system.entity.DapSystemDatasource;
import cn.com.bluemoon.daps.system.entity.DapSystemDatasourceEnvironment;
import cn.com.bluemoon.daps.system.entity.DapSystemInfo;
import cn.com.bluemoon.daps.system.mapper.DapSystemDatasourceMapper;
import cn.com.bluemoon.daps.system.mapper.DapSystemInfoMapper;
import cn.com.bluemoon.daps.system.service.DapSystemDatasourceEnvironmentService;
import cn.com.bluemoon.daps.system.service.DapSystemDatasourceService;
import cn.com.bluemoon.daps.system.vo.SysDataSourceConnInfo;
import cn.com.bluemoon.daps.system.vo.SysDatasourceVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统数据源表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-08-03
 */
@Slf4j
@Service
public class DapSystemDatasourceServiceImpl extends ServiceImpl<DapSystemDatasourceMapper, DapSystemDatasource> implements DapSystemDatasourceService {

    @Resource
    DapSystemDatasourceMapper dapSystemDatasourceMapper;

    @Resource
    DapSystemDatasourceEnvironmentService dapSystemDatasourceEnvironmentService;

    @Resource
    DapSystemInfoMapper dapSystemInfoMapper;
    /**
     * 查询系统数据源接口带模糊搜索和分页条件
     * @param pageSize
     * @param pageNum
     * @param sourceName
     * @return
     */
    public IPage<DapSystemDatasource> getDatasourcePageList(Integer pageSize, Integer pageNum, String sourceName){

        // 分页条件
        IPage<DapSystemDatasource> pageList = dapSystemDatasourceMapper
                .selectPage(new Page(pageNum, pageSize), new LambdaQueryWrapper<DapSystemDatasource>()
                .like(StringUtils.isNotEmpty(sourceName), DapSystemDatasource::getName, sourceName)
                .eq(DapSystemDatasource::getBmStatus, BmStatus.ON.getCode())
                .orderByDesc(DapSystemDatasource::getUpdateTime,DapSystemDatasource::getCreateTime));
        if(!pageList.getRecords().isEmpty()){
            Set<String> systemIds = pageList.getRecords().stream().map(DapSystemDatasource::getSystemInfoId).collect(Collectors.toSet());
            List<DapSystemInfo> dapSystemInfos = dapSystemInfoMapper.selectBatchIds(systemIds);
            Map<String, String> map = dapSystemInfos.stream().collect(Collectors.toMap(DapSystemInfo::getId, DapSystemInfo::getName));
            List<DapSystemDatasource> datasourceList = pageList.getRecords().stream().peek(p -> p.setSystemInfoId(map.get(p.getSystemInfoId()))).collect(Collectors.toList());
            pageList.setRecords(datasourceList);
        }
        return pageList;

    }

    /**
     * 获取所有的数据源信息
     * @return
     */
    @Override
    public List<DapSystemDatasource> getAllDatasource(String sysId) {

        // 如何id为0，则查询未被引用的数据源信息，否则查询被其他系统引用的数据源.
        List<DapSystemDatasource> systemDatasource = getBaseMapper().
                selectList(new LambdaQueryWrapper<DapSystemDatasource>().
                eq(DapSystemDatasource::getBmStatus, BmStatus.ON.getCode()).
                eq(DapSystemDatasource::getSystemInfoId,sysId));
        return systemDatasource;
    }

    @Override
    public boolean isUse(List<String> ids, String systemId) {

        List<DapSystemDatasource> list = new ArrayList<>();
        ids.forEach(id->{
            DapSystemDatasource dapSystemDatasource = new DapSystemDatasource();
            dapSystemDatasource.setSystemInfoId(systemId);
            dapSystemDatasource.setId(id);
            list.add(dapSystemDatasource);
        });
        return updateBatchById(list);
    }

    /**
     * 查询单个系统所引用的数据源
     * @param systemId
     * @return
     */
    @Override
    public List<DapSystemDatasource> getUseDatasource(String systemId) {

        List<DapSystemDatasource> systemDatasource = dapSystemDatasourceMapper
                .selectList(new LambdaQueryWrapper<DapSystemDatasource>()
                .eq(DapSystemDatasource::getSystemInfoId, systemId)
                .eq(DapSystemDatasource::getBmStatus, BmStatus.ON.getCode()));
        return systemDatasource;
    }

    /**
     * 新增数据源
     * @param dapSystemDatasource
     */
    @Override
    @Transactional(rollbackFor = {DapException.class, Exception.class})
    public ResultBean<Boolean> insertDatasource(DapSystemDatasource dapSystemDatasource){

        if(dapSystemDatasource.getUsable() == 0 || dapSystemDatasource.getUsable() == 1){
            DapSystemDatasource source = getBaseMapper().selectOne(new LambdaQueryWrapper<DapSystemDatasource>()
                    .eq(DapSystemDatasource::getName, dapSystemDatasource.getName())
                    .eq(DapSystemDatasource::getBmStatus, BmStatus.ON.getCode()));
            if(source == null || source.getId().equals(dapSystemDatasource.getId())){
                return ResultBean.ok(this.saveOrUpdate(dapSystemDatasource));
            }else{
                return ResultBean.error("数据源名称重复");
            }
        }
        return ResultBean.error("数据源用途只能为0或1");

    }

    /**
     * 删除数据源(可批量)
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public ResultBean<Boolean> deleteBatchSource(List<String> ids) {

        List<DapSystemDatasource> systemDatasource = getBaseMapper().selectBatchIds(ids);
        // 被引用的数据源
        List<DapSystemDatasource> unUseDatasource = systemDatasource.stream()
                .filter(s ->s.getBmStatus() == BmStatus.ON && !s.getSystemInfoId().equals("0"))
                .collect(Collectors.toList());
        if(!unUseDatasource.isEmpty()){
            // 获取引用的系统id
            Set<String> systemIds = unUseDatasource.stream().map(DapSystemDatasource::getSystemInfoId).collect(Collectors.toSet());
            // 查询系统信息
            List<DapSystemInfo> dapSystemInfos = dapSystemInfoMapper.selectBatchIds(systemIds);
            Map<String, String> sysMap = dapSystemInfos.stream().collect(Collectors.toMap(DapSystemInfo::getId, DapSystemInfo::getName));
            List<String> error = unUseDatasource.stream().map(d -> String.format("数据源%s被系统%s引用", d.getName(),
                            sysMap.get(d.getSystemInfoId()))).collect(Collectors.toList());
            return ResultBean.error(error.toString()+"，无法删除！");
        }
        List<DapSystemDatasource> datasourceList = systemDatasource.stream().map(s -> {
            DapSystemDatasource datasource = new DapSystemDatasource();
            datasource.setId(s.getId());
            datasource.setBmStatus(BmStatus.DELETE);
            return datasource;
        }).collect(Collectors.toList());
        // 同时删除数据源连接信息
        dapSystemDatasourceEnvironmentService.update(new LambdaUpdateWrapper<DapSystemDatasourceEnvironment>()
                .in(DapSystemDatasourceEnvironment::getDatasourceId, ids)
                .eq(DapSystemDatasourceEnvironment::getBmStatus, BmStatus.ON.getCode())
                .set(DapSystemDatasourceEnvironment::getBmStatus, BmStatus.DELETE.getCode()));
        // 批量删除
        return ResultBean.ok(this.updateBatchById(datasourceList));
    }

    @Override
    @Cacheable(keyGenerator = DapConstant.CACHE_KEY_GENERATOR, cacheNames = DapConstant.DapSystem.CACHE_NAME)
    public Optional<DapSystemDatasource> getCacheOneById(String id) {
        return Optional.ofNullable(getById(id));
    }

    /**
     * v1.3 版本 获取数据源以及数据源环境信息
     * @param id
     * @return
     */
    @Override
    public DatasourceDto getDatasourceInfo(String id) {

        // 查询数据源信息
        DapSystemDatasource datasource = dapSystemDatasourceMapper.selectById(id);
        // 查询数据源环境信息 过滤掉独立源库信息
        List<DapSystemDatasourceEnvironment> dapSystemDatasourceEnvironments = dapSystemDatasourceEnvironmentService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapSystemDatasourceEnvironment>()
                        .eq(DapSystemDatasourceEnvironment::getDatasourceId, id)
                        .eq(DapSystemDatasourceEnvironment::getIsInfoResource, 0)
                        .eq(DapSystemDatasourceEnvironment::getBmStatus, BmStatus.ON.getCode())
                        .orderByAsc(DapSystemDatasourceEnvironment::getEnvironment));
        DatasourceDto datasourceDto = new DatasourceDto();
        datasourceDto.setDapSystemDatasource(datasource);
        datasourceDto.setList(dapSystemDatasourceEnvironments);
        return datasourceDto;
    }

    @Override
    public List<DatasourceDto> getDatasourceInfoList(List<String> ids) {

        // 查询数据源信息
        List<DapSystemDatasource> datasourceList = dapSystemDatasourceMapper.selectBatchIds(ids);
        // 查询数据源环境信息
        List<DapSystemDatasourceEnvironment> dapSystemDatasourceEnvironments = dapSystemDatasourceEnvironmentService.getBaseMapper()
                .selectList(new LambdaQueryWrapper<DapSystemDatasourceEnvironment>().in(DapSystemDatasourceEnvironment::getDatasourceId, ids)
                        .eq(DapSystemDatasourceEnvironment::getBmStatus, BmStatus.ON.getCode()));
        List<DatasourceDto> list = new ArrayList();
        datasourceList.forEach(d -> {
            List<DapSystemDatasourceEnvironment> collect = dapSystemDatasourceEnvironments.stream()
                    .filter(e -> d.getId().equals(e.getDatasourceId())).collect(Collectors.toList());
            DatasourceDto datasourceDto = new DatasourceDto();
            datasourceDto.setDapSystemDatasource(d);
            datasourceDto.setList(collect);
            list.add(datasourceDto);
        });
        return list;
    }

    @Override
    public IPage<SysDatasourceVo> datasourcePage(Integer pageSize, Integer pageNum, String sourceName) {
        List<SysDatasourceVo> systemDatasourceVos = dapSystemDatasourceMapper.selectDataSources(sourceName);
        IPage<SysDatasourceVo> res = bmLogicPage(systemDatasourceVos, pageNum, pageSize);
        return res.convert(each -> {
            String dataSourceConnInfo = each.getConnInfos().stream().map(SysDataSourceConnInfo::toString).collect(Collectors.joining("\n"));
            each.setDataSourceConnInfo(dataSourceConnInfo);
            return each;
        });
    }
}
